﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Colorful.Furniture.BasicDataManagement;
using Colorful.Furniture.Enum;
using Colorful.Furniture.ErpCustomerManagement;
using Colorful.Furniture.ErpOrderManagement;
using Colorful.Furniture.Extensions;
using Colorful.Furniture.InterfaceDownstream;
using Colorful.Furniture.ResultManagement;
using Colorful.Furniture.View;
using FreeSql;
using Hangfire;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Uow;

namespace Colorful.Furniture.BackgroundManagement;

/// <summary>
/// 后台作业-订单提交
/// </summary>
public class RechargeJob : BackgroundJob<RechargeJobArgs>, ISingletonDependency
{

    private readonly IFreeSql _freeSql;
    private readonly IObjectMapper _objectMapper;
    private readonly ILogger<CustomerLog> _logger;
    private readonly IDatabase _redisDb;
    private readonly IBaseRepository<RechargeOrder> _rechargeOrderRepository;
    private readonly SubmitSupplierService _submitSupplierService;
    private readonly OrderInfoService _orderInfoService;
    private readonly IBackgroundJobManager _backgroundJob;
    private readonly FileConfig _fileConfig;
    private readonly OrderWithSupplierService _orderWithSupplierService;

    public RechargeJob(
        IFreeSql freeSql,
        IObjectMapper objectMapper,
        ILogger<CustomerLog> logger,
        IConnectionMultiplexer connectionMultiplexer,
        IBaseRepository<RechargeOrder> rechargeOrderRepository,
        SubmitSupplierService submitSupplierService,
        OrderInfoService orderInfoService,
        IBackgroundJobManager backgroundJob,
        IOptions<FileConfig> fileConfig,
        OrderWithSupplierService orderWithSupplierService
    )
    {
        _freeSql = freeSql;
        _objectMapper = objectMapper;
        _logger = logger;
        _redisDb = connectionMultiplexer.GetDatabase();
        _rechargeOrderRepository = rechargeOrderRepository;
        _submitSupplierService = submitSupplierService;
        _orderInfoService = orderInfoService;
        _backgroundJob = backgroundJob;
        _fileConfig = fileConfig.Value;
        _orderWithSupplierService = orderWithSupplierService;
    }

    /// <summary>
    /// 执行订单提交操作
    /// </summary>
    /// <param name="args"></param>
    public override async void Execute(RechargeJobArgs args)
    {
        _logger.LogWarning($"后台作业：开始执行【提交订单】 - 订单编号：{args.OrderNo}");

        var uow = _freeSql.CreateUnitOfWork();
        uow.IsolationLevel = IsolationLevel.ReadUncommitted;

        //查询订单是否创建成功
        var orderInfo = await _freeSql.Select<RechargeOrder>()
            .Where(x => x.OrderDownNo == args.OrderNo)
            .WithTransaction(uow.GetOrBeginTransaction())
            .ToOneAsync();
        if (orderInfo == null) //订单不存在，执行创建订单操作
        {
            var redis = await _redisDb.StringGetAsync($"{_fileConfig.RedisName}:Order:{args.OrderNo}");
            if (redis.HasValue)
            {
                //反序列化缓存订单信息
                var input = JsonDeserialize<RedisOrderInputDto>(redis);
                //是否为超时提交：客户提交时间+1分钟 小于 当前时间
                if (input.RechargeTime.ToDateTime().AddMinutes(1) < DateTime.Now)
                {
                    _logger.LogWarning($"后台作业：结束执行【提交订单】，订单超时提交 - 订单编号：{args.OrderNo}");

                    ////推送失败回调
                    //await _backgroundJob.EnqueueAsync(new SentNotifyFailArgs
                    //{
                    //    NotifyUrl = input.NotifyUrl,
                    //    Remark = "充值失败",
                    //    Status = EnumOrderStatus.订单失败,
                    //    Code = input.MerchantId,
                    //    OutTradeNo = input.OutTradeNo,
                    //    RechargeAccount = input.RechargeAccount
                    //});

                }
                else //正常订单
                {
                    //检查下游提单状态
                    var orderResult = await CheckOrderInfo(input);

                    var insert = new RechargeOrder()
                    {
                        Id = new Guid(),
                        OrderDownNo = args.OrderNo,
                        OutTradeNo = input.OutTradeNo,
                        RechargeAccount = input.RechargeAccount,
                        Qty = input.Number,
                        Price = orderResult.Price,
                        TotalPrice = input.PayAmount != 0 ? input.PayAmount : orderResult.TotalPrice,
                        ServiceFee = orderResult.ServiceFee,
                        IsPostSupplier = 0,
                        NotifyUrl = input.NotifyUrl,
                        CustomerId = orderResult.CustomerId,
                        CustomerCode = orderResult.CustomerCode,
                        CustomerName = orderResult.CustomerName,
                        Remark = orderResult.Message,
                        ProductName = orderResult.ProductName,
                        ProductNo = orderResult.ProductNo,
                        ProductId = orderResult.ProductId,
                        EndCustomerIp = input.EndCustomerIp,
                        ProductType = orderResult.ProductType,
                        PayAmount = input.PayAmount != 0 ? input.PayAmount : 0
                    };

                    if (orderResult.Message != "") //下游提单失败
                    {
                        insert.FinishTime = DateTime.Now;
                        insert.Status = EnumOrderStatus.充值失败;

                        //插入订单表
                        await _freeSql.Insert(insert).WithTransaction(uow.GetOrBeginTransaction()).ExecuteAffrowsAsync();

                        uow.Commit();

                        //推送失败回调
                        await _backgroundJob.EnqueueAsync(new SentNotifyArgs
                        {
                            OrderNo = args.OrderNo
                        }, BackgroundJobPriority.Normal, TimeSpan.FromSeconds(1));
                    }

                }

            }

            uow.Commit();

        }
        else
        {
            uow.Commit();

            _logger.LogWarning($"后台作业：结束执行【提交订单】，订单已存在 - 订单编号：{args.OrderNo}");
        }




    }



    /// <summary>
    /// 检查订单是否提单成功
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<CheckOrderDto> CheckOrderInfo(RedisOrderInputDto input)
    {
        var result = new CheckOrderDto();

        //检查商户信息
        var customerInfo = await _freeSql.Select<Customer>()
            .Where(x => x.Code == input.MerchantId)
            .FirstAsync();
        if (customerInfo == null)
        {
            return new CheckOrderDto()
            {
                Message = $"无效商户信息，商户号:【{input.MerchantId}】不存在"
            };
        }
        else
        {
            result.CustomerId = customerInfo.Id;
            result.CustomerCode = customerInfo.Code;
            result.CustomerName = customerInfo.Name;
            
            //订单查重
            var orderCount = await _freeSql.Select<RechargeOrder>()
                .Where(x => x.OutTradeNo == input.OutTradeNo && x.CustomerId == customerInfo.Id)
                .FirstAsync();
            if (orderCount != null)
            {
                result.Message = $"【{input.OutTradeNo}】订单重复";
                return result;
            }

            //签名校验
            var signTemp = $"{input.MerchantId}{input.OutTradeNo}{input.ProductNo}{input.RechargeAccount}{customerInfo.Key}";
            var sign = Md5Encrypt.Md5Encrypt32($"{input.MerchantId}{input.OutTradeNo}{input.ProductNo}{input.RechargeAccount}{customerInfo.Key}");

            if (sign != input.Sign && (input.MerchantId != 18662))
            {
                _logger.LogWarning($"客户订单编号:{input.OutTradeNo},签名校验失败");

                result.Message = $"签名校验失败";
                return result;
            }

            //获取商品关系视图
            var product = await _freeSql.Select<ViewInventory>()
                .Where(x => x.ProductNo == input.ProductNo && x.CustomerCode == input.MerchantId)
                .OrderByDescending(x => x.Sort)
                .OrderBy(x => x.ProductAddTime)
                .FirstAsync();
            if (product == null)
            {
                result.Message = $"【{input.ProductNo}】商品未开通";
                return result;
            }
            else
            {
                //赋值订单产品信息
                result.ProductId = product.ProductId;
                result.ProductNo = product.ProductNo;
                result.ProductName = product.ProductName;
                result.FaceAmount = product.FaceAmount;
                result.FaceRemark = product.FaceRemark;
                result.Price = product.SalePrice;
                result.TotalPrice = product.SalePrice * input.Number;
                result.ServiceFee = product.Commission == null || product.Commission == 0 ? 0 : (product.SalePrice * input.Number * product.Commission).ToRoundingOnlyEnter();
                result.ProductType = product.ProductType;
                result.PriceRemark = $"账户金额：{customerInfo.Price}，授信额度：{customerInfo.CreditPriceInitial}，冻结金额：{customerInfo.FrozenAmount}";

                if (product.MaxQty < input.Number || product.MinQty > input.Number)
                {
                    result.Message = $"【{input.ProductNo}】购买数量不符合要求";
                    return result;
                }
                else if (product.Status != 3)
                {
                    result.Message = $"【{input.ProductNo}】商品未上架";
                    return result;
                }
                else if (product.IsEnable != 1)
                {
                    result.Message = $"【{input.ProductNo}】通道未开启";
                    return result;
                }

                //检查邮箱格式
                if (product.IsCheckEmail == 1)
                {
                    int count = 0;
                    int index = 0;
                    while ((index = input.RechargeAccount.IndexOf("@163.com", index, StringComparison.Ordinal)) != -1)
                    {
                        count++; // 每次找到就增加计数器
                        index += "@163.com".Length; // 移动到下一个可能的匹配位置之后
                    }

                    int count2 = 0;
                    int index2 = 0;
                    while ((index2 = input.RechargeAccount.IndexOf("@126.com", index2, StringComparison.Ordinal)) != -1)
                    {
                        count2++; // 每次找到就增加计数器
                        index2 += "@126.com".Length; // 移动到下一个可能的匹配位置之后
                    }

                    if (count != 1 && count2 != 1)
                    {
                        result.Message = $"充值账号错误，必须是@163.com或@126.com邮箱格式";
                        return result;
                    }
                }

                // 成本金额不能大于销售金额
                if (product.SalePrice.ToDecimal() < product.CostPrice.ToDecimal())
                {
                    result.Message = $"【{input.ProductNo}】当前价格无匹配产品";
                    return result;
                }
                var totalPrice = product.SalePrice * input.Number;
                // 账户金额充足(账户余额 + 初始授信额度 - 冻结金额 > 产品售价)，才能提单成功
                if ((customerInfo.Price.ToDecimal() + customerInfo.CreditPriceInitial.ToDecimal() - customerInfo.FrozenAmount.ToDecimal()) < totalPrice.ToDecimal())
                {
                    result.Message = $"账户余额不足";
                    return result;
                }
                
                result.Message = "";
                return result;

            }

        }
        
    }


    /// <summary>
    /// JSON反序列化
    /// </summary>
    public static T JsonDeserialize<T>(string jsonString)
    {
        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
        MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
        T obj = (T)ser.ReadObject(ms);
        return obj;
    }


}

/// <summary>
/// 订单提交-操作体
/// </summary>
public class RechargeJobArgs
{
    /// <summary>
    /// 平台订单号
    /// </summary>
    public string OrderNo { get; set; }

}